#include "LZ78.h"

void Encoder(BITFILE* SourceFile, BITFILE* DestinationFile)
{
    uint16_t CurrentSon = 0;
    uint8_t Sample = 0;
    uint16_t Father = 0;
    uint16_t DictionaryIndex = 256;
    Node* Dictionary = HT_Init();
    
    if(bitfile_read(SourceFile, &Sample, CHARACTER) == 0)
    {
        printf("File is empty.No compression needed\n");
        bitfile_close(SourceFile);
        bitfile_close(DestinationFile);
        exit(0);
    }
        
    while(1)
    {
        if(DictionaryIndex >= HASHSIZE)
        {
            HT_Delete(Dictionary);
            Dictionary = HT_Init();
            DictionaryIndex = 256;
        }  

        CurrentSon = HT_Lookup(Dictionary, Sample, Father);
        
        if(CurrentSon != 0)
            
            Father = CurrentSon;
        
        else 
        {
            HT_Add(Dictionary, Sample, Father, DictionaryIndex);
            bitfile_write(DestinationFile, (unsigned char*)(&Father), MinBits(DictionaryIndex++));
            
            Father = HT_Lookup(Dictionary, Sample, 0);
        }
        
        if(bitfile_read(SourceFile, &Sample, CHARACTER) == 0)
        {  
            bitfile_write(DestinationFile, (unsigned char*)(&Father), MinBits(DictionaryIndex++));
            break;
        }
    }
    
    Father = 0;
    
    if(DictionaryIndex >= HASHSIZE)
    {
         HT_Delete(Dictionary);
         Dictionary = HT_Init();
         DictionaryIndex = 256;
    }
    
    bitfile_write(DestinationFile, (unsigned char*)(&Father), MinBits(DictionaryIndex++));
 
    bitfile_close(SourceFile);
    bitfile_close(DestinationFile);
    
    printf("Compression successfully finished\n");
}

void Decoder(BITFILE* SourceFile, BITFILE* DestinationFile)
{
    uint16_t ReadDictionaryIndex = 256;
    uint16_t CurrentNode = 0;
    uint16_t OldNode = 0;
    uint8_t B = 0;
    uint8_t* tmpstring = NULL;

    DNode* Dictionary = CreateDecDictionary();

    if(bitfile_read(SourceFile, (unsigned char*)&CurrentNode, MinBits(ReadDictionaryIndex++)) == 0)
    {
        printf("File is empty.No decompression needed\n");
        bitfile_close(SourceFile);
        bitfile_close(DestinationFile);
        exit(0);
    }
    
    bitfile_write(DestinationFile, (unsigned char*)(Dictionary[CurrentNode].String), CHARACTER * Dictionary[CurrentNode].Lenght);

    OldNode = CurrentNode;
    
    if(bitfile_read(SourceFile, (unsigned char*)&CurrentNode, MinBits(ReadDictionaryIndex++)) == 0 || CurrentNode == 0)
    {
        printf("Decompression successfully finished\n");
        bitfile_close(SourceFile);
        bitfile_close(DestinationFile);
        exit(0);
    }
    
    while(1)
    {
        if(Dictionary[CurrentNode].String != NULL) 
        {
            bitfile_write(DestinationFile, (unsigned char*)(Dictionary[CurrentNode].String),CHARACTER * Dictionary[CurrentNode].Lenght);  
            B = Dictionary[CurrentNode].String[0];
            tmpstring = CreateString(Dictionary[OldNode].String, B, Dictionary[OldNode].Lenght + 1);
            DecAdd(Dictionary, (ReadDictionaryIndex - 2), tmpstring, Dictionary[OldNode].Lenght + 1);
        } 
        else 
        {
            B = Dictionary[OldNode].String[0];
            tmpstring = CreateString(Dictionary[OldNode].String, B, Dictionary[OldNode].Lenght + 1);
            DecAdd(Dictionary, (ReadDictionaryIndex - 2), tmpstring, Dictionary[OldNode].Lenght + 1);
            bitfile_write(DestinationFile, (unsigned char*)(Dictionary[(ReadDictionaryIndex - 2)].String),CHARACTER * Dictionary[(ReadDictionaryIndex - 2)].Lenght);
        }
        
        ReadDictionaryIndex++;
        OldNode = CurrentNode;
        CurrentNode = 0;
        
	    if(ReadDictionaryIndex > HASHSIZE)
        {
            ReadDictionaryIndex = 256;
            OldNode = 0;
            FlushDec(Dictionary);
            
            if(bitfile_read(SourceFile, (unsigned char*)&OldNode, MinBits(ReadDictionaryIndex++)) == 0 || OldNode == 0) break;   
            
            bitfile_write(DestinationFile, (unsigned char*)(Dictionary[OldNode].String), CHARACTER * Dictionary[OldNode].Lenght);
            ReadDictionaryIndex++;
        }
        
        if(bitfile_read(SourceFile, (unsigned char*)&CurrentNode, MinBits(ReadDictionaryIndex - 1)) == 0 || CurrentNode == 0 ) break;
    }
    
    printf("Decompression successfully finished\n");
    
    bitfile_close(SourceFile);
    bitfile_close(DestinationFile);
}

uint8_t MinBits(uint16_t DictionaryIndex)
{
    double tmp = log2(DictionaryIndex + 1);
	uint8_t ret = log2(DictionaryIndex + 1);
    
	if( tmp > ret )
		return (ret + 1);
    
	return (ret == 0 ? 1 : ret);
}
